<?php
// @formatter:off
/**
 * @file WCGroupsHolder.php
 * @author Alejandro Dario Simi
 * @date $Date: 2013-07-07 18:03:56 +0000 (Sun, 07 Jul 2013) $
 *
 * $Id: WCGroupsHolder.php 91 2013-07-07 18:03:56Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/tags/wcomix-1.0-BETA2/includes/holders/WCGroupsHolder.php $
 */
// @formatter:on

require_once "{$wcPaths["includes-directory"]}/representations/WCGroup.php";

/**
 * @class WCGroupsHolder
 */
class WCGroupsHolder {
	/**
	 * @var WCGroupsHolder
	 */
	protected static $_Instance;

	/**
	 * @var array()
	 */
	protected $_groups;
	/**
	 * @var array()
	 */
	protected $_groupsInverted;
	/**
	 * @var int
	 */
	protected $_time;
	/**
	 * @var PDO
	 */
	protected $_db;
	/**
	 * @var string
	 */
	protected $_dbprefix;
	/**
	 * @var WCContainer List of public groups.
	 */
	protected $_public = false;

	protected function __construct() {
		global $wcDatabaseAccess;

		$this->_db = WCConnection::Instance();
		$this->_dbprefix = $wcDatabaseAccess['prefix'];

		$this->_groups = false;
		$this->_groupsInverted = false;
		$this->load();
	}
	public function __destruct() {
		unset($this->_groups);
		unset($this->_groupsInverted);
	}
	/**
	 * Prevent users to clone the instance.
	 */
	public function __clone() {
		trigger_error(__CLASS__.": Clone is not allowed.", E_USER_ERROR);
	}
	//
	// Public methods
	/**
	 * Creates a new group with default configurations
	 *
	 * @param string $name Name for the group.
	 * @param string $directory Root directory.
	 * @param string $trash Subdirectory where garbage has to be dropped.
	 * @return int Returns the id for the new group. On failure, returns false.
	 */
	public function add($name, $directory, $trash) {
		//
		// Loading global pointers.
		global $wcDefaults;
		global $wcDirectoriesHolder;
		//
		// Setting default value to be returned.
		$id = false;
		//
		// Checking that Read Only Mode is not activated.
		if(!$wcDefaults["read-only"]) {
			//
			// Building group's root directory full path.
			$directory = WCSanitizer::SystemPath($directory);
			//
			// Building group's trash directory full path.
			$trashPath = WCSanitizer::SystemPath("{$directory}{$trash}");
			//
			// Checking that:
			//	- The root directory is a valid directory.
			//	- If there's a trash directory specified, it is a
			//	  valid directory.
			if(is_dir($directory) && (!$trash || is_dir($trashPath))) {
				//
				// Creating a query to insert the new item.
				// @{
				$query = "insert\n";
				$query .= "        into {$this->_dbprefix}groups (\n";
				$query .= "                grp_name, grp_root, grp_trash)\n";
				$query .= "        values (:name, :directory, :trash)\n";

				$stmt = $this->_db->prepare("WCGroupsHolder::add", $query);
				// @}
				//
				// Building database parameters.
				$params = array(
					":name" => $name,
					":directory" => $directory,
					":trash" => $trash
				);
				//
				// Attempting to create the new group.
				if($stmt->execute($params)) {
					//
					// At this point, group was created.
					$id = $this->_db->lastInsertId();
				}
			}
			//
			// Reloading all groups.
			$this->load();
			//
			// When a new group is created it has no directories,
			// therefore, it is force to have it's first one.
			if($id) {
				//
				// Always, first directory is slash... no, not the
				// guitarist.
				$dirname = "/";
				//
				// Getting the new group.
				$group = $this->groupById($id);
				//
				// Adding the first directory.
				$wcDirectoriesHolder->create($dirname, $group);
			}
			//
			// Adding trash directory.
			if($id && $trash) {
				//
				// Getting the new group.
				$group = $this->groupById($id);
				//
				// Adding trash directory.
				$wcDirectoriesHolder->create($trash, $group);
			}
		}
		//
		// Returning newly created object.
		return $id;
	}
	public function countOfById($id) {
		if(isset($this->_groups[$id])) {
			return $this->_groups[$id]->count();
		} else {
			return false;
		}
	}
	public function countOfByName($name) {
		if(isset($this->_groupsInverted[$name])) {
			return $this->countOfById($this->_groupsInverted[$name]);
		} else {
			return false;
		}
	}
	public function db() {
		return $this->_db;
	}
	public function directoriesOfById($id) {
		if(isset($this->_groups[$id])) {
			return $this->_groups[$id]->directories();
		} else {
			return array();
		}
	}
	public function directoriesOfByName($name) {
		if(isset($this->_groupsInverted[$name])) {
			return $this->directoriesOfById($this->_groupsInverted[$name]);
		} else {
			return false;
		}
	}
	/**
	 * @param integer $id
	 * @return WCGroup
	 */
	public function groupById($id) {
		if(isset($this->_groups[$id])) {
			return $this->_groups[$id];
		} else {
			return false;
		}
	}
	/**
	 * @param string $name
	 * @return WCGroup
	 */
	public function groupByName($name) {
		if(isset($this->_groupsInverted[$name])) {
			return $this->groupById($this->_groupsInverted[$name]);
		} else {
			return null;
		}
	}
	public function groupId($name) {
		if(isset($this->_groupsInverted[$name])) {
			return $this->_groupsInverted[$name];
		} else {
			return null;
		}
	}
	public function groupIds() {
		return array_values($this->_groupsInverted);
	}
	public function groupName($id) {
		if(isset($this->_groups[$id])) {
			return $this->_groups[$id]->name();
		} else {
			return false;
		}
	}
	/**
	 * This methods allows to obtain all system configured groups.
	 *
	 * @return multitype:WCGroup List of loaded groups.
	 */
	public function & groups() {
		return $this->_groups;
	}
	/**
	 * This method allows to get a list of public groups..
	 *
	 * @return WCGroup[] Returns a list of public groups.
	 */
	public function publicGroups() {
		return $this->_public->items();
	}
	public function reload() {
		return $this->load();
	}
	//
	// Protected methods
	/**
	 * The method creates all required containers.
	 */
	protected function createContainers() {
		//
		// Public group container.
		if($this->_public == false) {
			//
			// Creating a list for public groups.
			$this->_public = new WCContainer($this);
		}
	}
	protected function load() {
		$this->createContainers();
		$this->_groups = array();
		$this->_groupsInverted = array();

		$query = "select  grp_id,\n";
		$query .= "        grp_name\n";
		$query .= "from    {$this->_dbprefix}groups\n";
		$query .= "order by grp_name asc";

		$stmt = $this->_db->prepare(__CLASS__."::".__FUNCTION__, $query);

		if($stmt->execute(array())) {
			foreach($stmt->fetchAll() as $row) {
				$this->_groups[$row['grp_id']] = new WCGroup($this, $row['grp_id']);
				$this->_groupsInverted[$row['grp_name']] = $row['grp_id'];
				if($this->_groups[$row['grp_id']]->isPublic()) {
					$this->_public->addItem($row['grp_id'], $this->_groups[$row['grp_id']]);
				}
			}
		}
	}
	//
	// Public class methods
	public static function Instance() {
		if(!isset(self::$_Instance)) {
			$c = __CLASS__;
			self::$_Instance = new $c();
		}

		return self::$_Instance;
	}
}
?>